/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uk.ac.bath.schemes;


import uk.ac.bath.legacy.Gene;
import java.util.Arrays;
import uk.ac.bath.environment.MachineIF;
import uk.ac.bath.environment.Fitness;
import uk.ac.bath.environment.Scheme;
import uk.ac.bath.util.MyRandom;

/**
 *
 * @author pjl
 */
public class DiverseSaneScheme implements  Scheme{

    SaneSubGene genes[];
    private SaneSubGene[] net_pop;
    float best;
    int generation;
    int iTrial = 0;
  
    boolean done = false;
   
    private SaneBuilder builder;
    int nPop;
    private int numBreed;
    private int trialsPerGeneration;

    public DiverseSaneScheme(int nPop, int nBreed, int trailsPerGeneration,  BuilderIF builder) throws Exception {
       
        numBreed = nBreed;
        if (3 * nBreed > nPop) {
            throw new Exception(" Too many breeders max is" + nPop / 3);
        }
        this.trialsPerGeneration = trailsPerGeneration;
        this.builder = (SaneBuilder)builder;
        //      this.evaluator = eval;
        this.nPop = nPop;
        genes = new Gene[nPop];
     //   tweaks.addAll(eval.getTweaks());
     //   init();
    }

    @Override
    public void init() {

   
        done = false;
        iTrial = 0;
        generation = 0;

        //       evaluator.requestReset();

        best = 0.0f;
        for (int i = 0; i < nPop; i++) {
            genes[i] = (SaneSubGene)builder.createSaneRandomSubGene(); //builder.bitsPerGene(), true);
        }
        net_pop = builder.createSaneGeneArray();
        this.best = 0.0f;
    }

//    public Network nextNetwork() {
//
//
//    }
    private MachineIF createRandomNet() {
        /*find random subpopulation*/
        for (int j = 0; j < net_pop.length; ++j) {
            net_pop[j] = genes[MyRandom.nextInt(nPop)];
            net_pop[j].tests++;
        }

        MachineIF net = builder.build(net_pop);    /*form the network*/
        return net;
    }

    private void nextGeneration() {

        generation++;
        /*get average fitness level.  Multiply by 100 to get more resolution*/

        for (int i = 0; i < nPop; ++i) {
            if (genes[i].tests > 0) {
                genes[i].fitness = (float) ((genes[i].fitness * 100.0) / genes[i].tests);
            } else {
                genes[i].fitness = 0;
            }
        }


        Arrays.sort(genes, Gene.rev);

        for (int i = 0; i < numBreed; i++) {
            SaneSubGene a = genes[i];
            int nn = i;
            if (i == 0) {
                nn = numBreed;
            }
            SaneSubGene b = genes[MyRandom.nextInt(nn)];



            SaneSubGene a1 = genes[numBreed + 2 * i];
            SaneSubGene b1 = genes[numBreed + 2 * i + 1];

            builder.crossOver(a, b, a1, b1);

        }

        for (int i = 3 * numBreed; i < nPop; i++) {
            genes[i] = (SaneSubGene)builder.createSaneRandomSubGene();
        }

        for (SaneSubGene g : genes) {
            g.fitness = 0.0f;
            g.tests = 0;
        }

    }

    @Override
    public void endOfEvaluation(Fitness fit) {

    
        /* add fitness to each participating neuron's fitness variable*/

        for (int j = 0;
                j < net_pop.length;
                ++j) {
            net_pop[j].fitness += fit.fitness;
        }


        if (iTrial == trialsPerGeneration) {
            nextGeneration();
            iTrial = 0;
        }
        iTrial++;

        //fitness = Float.MAX_VALUE;

//        currentMachine = createRandomNet();
//
//        evaluator.nextEvaluation(currentMachine);

    }

    public MachineIF nextMachine() {
       return createRandomNet();
    }

    public String getStatus() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public String reportSetup() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

//    public Vector<Cell> getPopulation() {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//    public View createSimulationView() {
//        return evaluator.createView();
//    }
//
//    public Vector<Cell> getPopulation() {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
////    @Override
////    protected void setFitness(float fitness) {
////        throw new UnsupportedOperationException("Not supported yet.");
////    }
//
//    public void zap() {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }

//    @Override
//    public void nextEvaluation(Fitness fit) {
//        processEndOfEvaluation(fit); //    throw new UnsupportedOperationException("Not supported yet.");
//    }
}


